#ifndef CONFIG_LOADER_H
#define CONFIG_LOADER_H
#include <sstream>
#include <string>
#include <list>
#include <map>

enum varType_t{
    VAR_INT = 0,
    VAR_FLOAT,
    VAR_STRING,
    VAR_BOOL
};

struct Var{
    int _int;
    float _float;
    bool _bool;
    std::string str;
    varType_t type;
};

typedef std::map<std::string, Var> Table;

class ConfigLoader{
    public:
        ConfigLoader(const char*);
        ~ConfigLoader();

        void Prase();
        template<class T>
        T getVar(std::string);
        template<class T, class T1>
        T getTableVar(std::string, T1);
        //int getVar(std::string);
        //float getVar(std::string);

    private:
        std::string deleteAllChars(std::string, const char*);
        template<class T>
        std::string to_string(T);

        typedef std::list<std::string>Stack;
        Stack stack;
        std::map<std::string, Var>vars;
        std::map<std::string, Table>t_vars;
        Table PraseTable(std::string);
};

template<class T>
std::string ConfigLoader::to_string(T val){
    std::stringstream ret;
    ret<<val;
    return ret.str();
}

template<class T>
T ConfigLoader::getVar(std::string index){
    std::map<std::string, Var>::iterator it = vars.find(index);
    void* ret;

    if(it != vars.end()){
        switch(it->second.type){
            case VAR_FLOAT:
                ret = &it->second._float;
            break;
            case VAR_INT:
                ret = &it->second._int;
            break;
            case VAR_STRING:
                ret = &it->second.str;
            break;
            case VAR_BOOL:
                ret = &it->second._bool;
            break;
        }
    }else
        throw std::string("Variable \"" + index + "\" not found!");

    return *(T*)ret;
}

template<class T, class T1>
T ConfigLoader::getTableVar(std::string table, T1 index){
    std::map<std::string, Table>::iterator it = t_vars.find(table);
    void* ret;

    if(it != t_vars.end()){
        std::string inx = to_string<T1>(index);
        std::map<std::string, Var>::iterator itx = it->second.find(inx);

        if(itx == it->second.end())
            throw std::string("Table index not found!");

        switch(itx->second.type){
            case VAR_FLOAT:
                ret = &itx->second._float;
            break;
            case VAR_INT:
                ret = &itx->second._int;
            break;
            case VAR_STRING:
                ret = &itx->second.str;
            break;
            case VAR_BOOL:
                ret = &itx->second._bool;
            break;
        }
    }else
        throw std::string("Table \"" + table + "\" not found!");

    return *(T*)ret;
}

#endif //CONFIG_LOADER_H
